/*
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
#if !defined(_Basic_)
#define _Basic_

#include <xutility>
#include <typeinfo>
#include <assert.h>
#include <iostream>
#include <crtdefs.h>
#include <vector>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/pop_back.hpp>
#include <boost/mpl/same_as.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/timer.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/type_traits.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/limits.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/static_assert.hpp>


//#include <boost/thread/detail/singleton.hpp> // problem with boost threaded singleton and \clr option. A modified version is keeped here : take care, it may not be thread safe.
#include <src/doxygen/doxygen.h>
#include <src/miscellaneous/pattern/Singleton.h>
#include <src/math/Modulus.h>



struct Periodic			{
	static std::string get_name(){return " Periodic ";};
};
struct Dirichlet		{
	static std::string get_name(){return " Dirichlet ";};
};
struct Protected		{
	static std::string get_name(){return " Protected ";};
};
struct Unbounded		{
	static std::string get_name(){return " Unbounded ";};
};
struct Neumann		{
	static std::string get_name(){return " Neumann ";};
};

typedef boost::true_type OS_true;
typedef boost::false_type OS_false;

/*struct OS_false {}; 
struct OS_true {}; */


template <class T, typename CONST> 
struct const_helper {
	typedef typename const T type;
};
template <class T> 
struct const_helper<T, OS_false> {
	typedef typename T type;
};

struct  Null{};
struct  Null_Const{};


template<typename CONST>
struct Null_Helper {
	typedef Null type;
};
template<>
struct Null_Helper<OS_true> {
	typedef Null_Const type;
};


//#define array_c(type,size)		boost::array<type,size>   //boost start counting at 0
#define smart_ptr				boost::shared_ptr
#define weak_smart_ptr			boost::weak_ptr
#define Singleton				boost::detail::thread::singleton



#define IS_NULL(expr) ( ( ( expr ) > 0 ? ( expr ) : - (expr) ) < THRESHOLD )
#define IS_NEGATIVE(expr) ( expr < THRESHOLD)
#define IS_POSITIVE(expr) ( expr > -THRESHOLD)
//exception
struct OS_exception_type : public std::exception {
	static const char* what() {return "OS_exception_type";};
};
static OS_exception_type OS_exception;
// assert
// static assert
#define OS_STATIC_CHECK(expr)   BOOST_STATIC_ASSERT(expr)
#define OS_MPL_ASSERT(expr)		BOOST_MPL_ASSERT( (expr) )
// dynamic assert
#if defined(_DEBUG) 
#define OS_DYNAMIC_CHECK(cond, mesg) if (! (cond) ) { std::cout << std::endl << "debug exception " << OS_exception.what() << " : " << mesg << std::endl ; throw OS_exception;}
#else 
 #define OS_DYNAMIC_CHECK(cond, mesg) if (! (cond) ) { std::cout << std::endl << "release exception " << OS_exception.what() << " : " << mesg << std::endl ; throw OS_exception;}
//	#define OS_DYNAMIC_CHECK(cond, mesg) 
#endif

#define OS_double  double
#define OS_bool  bool
#define OS_size std::size_t
#define OS_int  int

static OS_double THRESHOLD = 1e-8;
static const OS_double const_zero_real(0.);
static OS_double zero_real(0.);  // argh...I need it

typedef boost::timer OS_timer;


#  ifndef M_SQRT_2
    #define M_SQRT_2    0.7071067811865475244008443621048490392848359376887
#  endif
#  ifndef M_1_SQRTPI
    #define M_1_SQRTPI  0.564189583547756286948
#  endif
#  ifndef M_SQRT2
    #define M_SQRT2     1.41421356237309504880
#  endif

#define OS_MIN_INTEGER         ((std::numeric_limits<OS_int>::min)())
#define OS_MAX_INTEGER         ((std::numeric_limits<OS_int>::max)())
#define OS_MIN_REAL           -((std::numeric_limits<OS_double>::max)())
#define OS_MAX_REAL            1./THRESHOLD
//#define OS_MAX_REAL            ((std::numeric_limits<OS_double>::max)())
#define OS_MIN_POSITIVE_REAL   ((std::numeric_limits<OS_double>::min)())
#define OS_EPSILON             ((std::numeric_limits<OS_double>::epsilon)())
#define OS_NULL_INTEGER        ((std::numeric_limits<OS_int>::max)())
#define OS_NULL_REAL           ((std::numeric_limits<float>::max)())


#define VectoR						boost::mpl::vector
#define PushFront(List,Insert)		boost::mpl::push_front<typename List,Insert>::type
#define PushBack(List,Insert)		boost::mpl::push_back<typename List,Insert>::type
#define PopBack(List)				boost::mpl::pop_back<typename List>::type
#define PopFront(List)				boost::mpl::pop_front<typename List>::type
#define IndexOf(List,element)		_Find_<List,element>::iter::pos::value   //boost start counting at 0
#define TypeAt(List,i)				typename boost::mpl::at_c<typename List,i>::type
#define IsSame(type1,type2)			boost::mpl::is_same<type1, type2>
#define IF(Condition, type1,type2)	boost::mpl::if_c<Condition, type1,type2>::type;
#define IS_INTEGRAL					boost::is_integral


namespace OS_detail{

	template<typename I1, typename I2, class T>
	struct copy_imp
	{
		inline I2 operator()(I1 first, I1 last, I2 out)
		{
		   while(first != last)
		   {
			  *out = *first;
			  ++out;
			  ++first;
		   }
		   return out;
		}
	};

	template<typename I1>
	struct copy_imp<I1,I1,OS_true>
	{
		typedef typename std::iterator_traits<I1>::value_type T;
		inline I1 operator()(I1 first, I1 last, I1 out)
		{
		   memcpy(out, first, (last-first)*sizeof(T));
		   return out+(last-first);
		}
	};
};
template<typename I1, typename I2>
inline I2 OS_copy(I1 first, I1 last, I2 out)
{
   // memcpy if T has a trivial assignment operator,
   typedef typename std::iterator_traits<I1>::value_type value_type;
   return OS_detail::copy_imp<I1,I2, boost::has_trivial_assign<value_type>::type>()(first,last,out);
}


template <class T>
class Plain_Data {
public :
	enum :OS_size{Dim = 0};
	typedef T															value_type;
	typedef T															base_value_type;
	typedef OS_true														Trivial;
	typedef T&															reference;
	typedef const T&													const_reference;
};


template<class T>
struct OS_type_helper {
	template<class T, class B>
	struct helper{
		typedef T type;
	};
	template<class T>
	struct helper<T,OS_true>
	{
		typedef Plain_Data<T> type;
	};
	typedef typename boost::is_fundamental<T>::type bool_type;
	typedef typename helper<T,bool_type>::type type;


	enum :OS_size{Dim = type::Dim};
	typedef typename type::value_type										value_type;
	typedef typename type::base_value_type									base_value_type;
	typedef typename type::reference										reference;
	typedef typename type::const_reference									const_reference;
};

template <class T, class Boundary = typename T::Boundary_type>
struct Dual {
	OS_STATIC_CHECK(false); // you have to implement it.
	typedef T type;
};

#endif //_Basic_